﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.IO;
using System.Drawing;
using System.Collections.ObjectModel;

namespace Mosiac_Desktop
{
    [Serializable()]
    public class WallpaperData
    {
        public ObservableCollection<String> Directories
        {
            get
            {
                if (m_oDirs != null)
                    return m_oDirs;
                else
                {
                    m_oDirs = new ObservableCollection<string>();
                    return m_oDirs;
                }
            }
            set { m_oDirs = value; }
        }
        public int ConstraintValue
        {
            get { return nConstraintValue; }
            set { nConstraintValue = value; }
        }

        public bool UseSubdirectories
        {
            get { return bUseSubdirectories; }
            set { bUseSubdirectories = value; }
        }

        public Wallpaper.Constraint Constraint
        {
            get { return eConstraint; }
            set { eConstraint = value; }
        }


        public int TimerValue
        {
            get { return nTimerValue; }
            set { nTimerValue = value; }
        }


        private ObservableCollection<String> m_oDirs;
        private int nConstraintValue;
        private Wallpaper.Constraint eConstraint;
        private int nTimerValue;
        private bool bUseSubdirectories;

        public WallpaperData()
        {
        }
    }

    public class Wallpaper
    {
        public Wallpaper() { }

        const int SPI_SETDESKWALLPAPER = 20;
        const int SPIF_UPDATEINIFILE = 0x01;
        const int SPIF_SENDWININICHANGE = 0x02;

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);

        private static Image GenerateThumbnail(int N, string sFileName, Constraint oConstraint)
        {
            try
            {
                Image image = null;
                // Check if textbox has a value
                if (sFileName != String.Empty)
                    image = Image.FromFile(sFileName);
                // Check if image exists
                if (image != null)
                {
                    int nWidth = 0;
                    int nHeight = 0;
                    if (oConstraint == Constraint.Width)
                    {
                        nWidth = N;
                        nHeight = (int)Math.Abs((decimal)N / image.Width * image.Height);
                    }
                    else
                    {
                        nHeight = N;
                        nWidth = (int)Math.Abs((decimal)N / image.Height * image.Width);
                    }

                    return ResizeImage(ref image, nWidth, nHeight);
                }
                return null;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// Resize the image to the specified width and height.
        /// </summary>
        /// <param name="image">The image to resize.</param>
        /// <param name="width">The width to resize to.</param>
        /// <param name="height">The height to resize to.</param>
        /// <returns>The resized image.</returns>
        public static System.Drawing.Bitmap ResizeImage(ref System.Drawing.Image poImage, int width, int height)
        {
            //a holder for the result
            Bitmap result = new Bitmap(width, height);

            //use a graphics object to draw the resized image into the bitmap
            using (Graphics graphics = Graphics.FromImage(result))
            {
                //set the resize quality modes to high quality for larger images
                if (width > 100 || height > 100)
                {
                    graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                    graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                }
                else
                {
                    graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
                    graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default;
                    graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
                }
                //draw the image into the target bitmap
                graphics.DrawImage(poImage, 0, 0, result.Width, result.Height);
            }
            poImage.Dispose();
            //return the resulting bitmap
            return result;
        }

        private static List<E> MixList<E>(List<E> inputList)
        {
            List<E> randomList = new List<E>();

            Random r = new Random();
            int randomIndex = 0;
            while (inputList.Count > 0)
            {
                randomIndex = r.Next(0, inputList.Count); //Choose a random object in the list
                randomList.Add(inputList[randomIndex]); //add it to the new, random list
                inputList.RemoveAt(randomIndex); //remove to avoid duplicates
            }

            return randomList; //return the new random list
        }


        public string StartDeskop(List<string> oDirs, int N, int WidthBounds, int HeightBounds, Constraint oConstraint, bool bSubdirectories)
        {
            
            List<string> oFilesList = new List<string>();
            string[] oFilters = { "*.jpg", "*.png", "*.gif", "*.bmp" };

            foreach (string sFoldername in oDirs)
            {
                if (sFoldername == null || sFoldername == "")
                    break;

                foreach (string sfilter in oFilters)
                {
                    oFilesList.AddRange(Directory.GetFiles(sFoldername, sfilter, bSubdirectories? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly));
                }

            }

            //randomize list
            oFilesList = MixList(oFilesList);

            Bitmap oWallPaper = new Bitmap(WidthBounds, HeightBounds);
            Graphics oGr = Graphics.FromImage(oWallPaper);

            Point oLastPoint = new Point(0, 0);
            int nMaxHeight = 0;
            bool bFirst = true;
            int nLastWidth = 0;

            Image oI = null;

            foreach (string f in oFilesList)
            {
                oI = GenerateThumbnail(N, f, oConstraint);
                if (oI.Height > nMaxHeight)
                    nMaxHeight = oI.Height;

                if (oLastPoint.Y + oI.Height > oWallPaper.Height)
                    break;

                if (oLastPoint.X + oI.Width > oWallPaper.Width)
                {
                    oLastPoint.Y = oLastPoint.Y + nMaxHeight;
                    oLastPoint.X = 0;
                    nMaxHeight = 0;
                    bFirst = true;
                }


                if (bFirst)
                {
                    oGr.DrawImage(oI, new Point(oLastPoint.X, oLastPoint.Y));
                    bFirst = false;
                }
                else
                {
                    oGr.DrawImage(oI, new Point(oLastPoint.X + nLastWidth, oLastPoint.Y));
                    oLastPoint = new Point(oLastPoint.X + nLastWidth, oLastPoint.Y);
                }
                nLastWidth = oI.Width;
            }
            oI = null;

            string oWallpaperFile = Wallpaper.Set(ref oWallPaper, Wallpaper.Style.Centered);
            oWallPaper = null;
            return oWallpaperFile;
        }

        public enum Constraint : int
        {
            Width,
            Height
        }

        public enum Style : int
        {
            Tiled,
            Centered,
            Stretched
        }

        public static string Set(ref System.Drawing.Bitmap poImg, Style style)
        {
            System.Random oRnd = new Random(); ;
            byte[] bytes = new byte[8];
            oRnd.NextBytes(bytes);
            long int64 = BitConverter.ToInt64(bytes, 0);
            ulong uint64 = BitConverter.ToUInt64(bytes, 0);


            string tempPath = Path.Combine(Path.GetTempPath(), "md__" +uint64.ToString() + ".bmp");
            try
            {
                poImg.Save(tempPath, System.Drawing.Imaging.ImageFormat.Bmp);
            }
            catch(ExternalException ex)
            {
                return "";
            }

            RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop", true);
            if (style == Style.Stretched)
            {
                key.SetValue(@"WallpaperStyle", 2.ToString());
                key.SetValue(@"TileWallpaper", 0.ToString());
            }

            if (style == Style.Centered)
            {
                key.SetValue(@"WallpaperStyle", 1.ToString());
                key.SetValue(@"TileWallpaper", 0.ToString());
            }

            if (style == Style.Tiled)
            {
                key.SetValue(@"WallpaperStyle", 1.ToString());
                key.SetValue(@"TileWallpaper", 1.ToString());
            }

            SystemParametersInfo(SPI_SETDESKWALLPAPER,
                0,
                tempPath,
                SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);

            //delete the old files
            /*
            List<string> oFilesList = new List<string>();

            oFilesList.AddRange(Directory.GetFiles(Path.GetTempPath(), "md__*.bmp"));

            foreach (string f in oFilesList)
            {
                if (f != tempPath)
                    File.Delete(f);
            }
            */
            return tempPath;
        }

        public static void Set(Uri uri, Style style)
        {
            System.IO.Stream s = new System.Net.WebClient().OpenRead(uri.ToString());

            System.Drawing.Image img = System.Drawing.Image.FromStream(s);
            string tempPath = Path.Combine(Path.GetTempPath(), "wallpaper.bmp");
            img.Save(tempPath, System.Drawing.Imaging.ImageFormat.Bmp);

            RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop", true);
            if (style == Style.Stretched)
            {
                key.SetValue(@"WallpaperStyle", 2.ToString());
                key.SetValue(@"TileWallpaper", 0.ToString());
            }

            if (style == Style.Centered)
            {
                key.SetValue(@"WallpaperStyle", 1.ToString());
                key.SetValue(@"TileWallpaper", 0.ToString());
            }

            if (style == Style.Tiled)
            {
                key.SetValue(@"WallpaperStyle", 1.ToString());
                key.SetValue(@"TileWallpaper", 1.ToString());
            }

            SystemParametersInfo(SPI_SETDESKWALLPAPER,
                0,
                tempPath,
                SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
        }
    }
}
